#pragma once
#ifndef OPTDATA_H
#define OPTDATA_H

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include "Structure.h"
#include "Tools.h"
#include "stdexcept"
#include <boost/filesystem.hpp>
#include <string>
#include <sstream>
#include <math.h>


using namespace std;
using namespace boost::filesystem;

struct SDij {
    int nPoint; //1D position 
    int nFieldID; //field name for which field is
    int nBeamletID; //beamlet ID for which beamlet is    
    double nContribution; //the beamlet contribution for this point 
};

typedef struct {
    int64_t m_nID;
    float m_fContrib;
} INFLU_ELEM;

class OptData {
public:
    /***************         constructor and destructor            ***************/
    OptData(void);
    OptData(const OptData &obj);
    ~OptData();

    OptData& operator =(OptData& obj);

    /***************            getter and setter                  ***************/
    void setDoseMatrixSize(unsigned int x, unsigned int y, unsigned int z) {
        this->m_nSizeX = x;
        this->m_nSizeY = y;
        this->m_nSizeZ = z;
    }

    void getDoseMatrixSize(unsigned int &x, unsigned int &y, unsigned int &z) {
        x = this->m_nSizeX;
        y = this->m_nSizeY;
        z = this->m_nSizeZ;
    }

    unsigned int getBeamletNumTotal(void) {
        return this->m_nBeamletNumTotal;
    }

    //unsigned int getWeightNumTotal(void)
    //{return this->m_nWeightNumTotal;}
    vector<int> getFieldBeamletNum(void) {
        return this->m_vFieldBeamletNum;
    }

    //add structure data in m_vStructures
    void addStructure(CStructure structure) {
        this->m_vStructures.push_back(structure);
    }

    vector<CStructure>* getStructures(void) {
        return &this->m_vStructures;
    }

    vector<vector<double> >* getDijTotal(void) {
        return &m_vDijTotal;
    }

    vector<double>* getWeightTotal(void) {
        return &this->m_vWeightTotal;
    }

    void setWeightTotal(vector<double> weights) {
        this->m_vWeightTotal = weights;
    }

    //store dose 
    vector<double>* getDose(void) {
        return &m_vDose;
    }

    //store EUD

    vector<double>* getEUD(void) {
        return &m_vEUD;
    }

    //void addField(CFieldDose &field);
    //return z * m_nSizeY * m_nSizeX + y* m_nSizeX + x;

    unsigned int position3DTo1D(unsigned int x, unsigned int y, unsigned int z) {
        return z * (this->m_nSizeY)*(this->m_nSizeX) + y * (this->m_nSizeX) + x;
    };

    /***************            calculate dose                      ***************/
    //vector<double> calculateDose(vector<double> *vWeight); 
    void calculateDose(vector<double> *vWeight);
    vector<double> calculateDVH(vector<double> *resultDose, CStructure structure, double dvhResolution = 0.01);
    //based on m_vDose and m_vStructures calculate EUD
    void calculateEUD(void);

    void inputDoseSize(string inDoseSizePath);
    void inputFieldType1(int fieldID, string inSpotFieldPath, string inSpotWeightPath); //first line dosegride size 100,69,84 others 40,25,10,1298,2.46423e-009
    void inputFieldType2(int fieldID, string inSpotFieldPath, string inSpotWeightPath); //no first line dosegride 9.0.1.0.317 0.0381065
    void inputField(int fieldID, string inSpotFieldPath, string inSpotWeightPath);
    bool inputFieldFromBin(int fieldID, string inSpotFieldPath, string inSpotWeightPath);
    void inputStructure(string structName, string inStructPath, double EUD);
    void inputDose(string inDosePath);


    //void outputWeight(map<int,double> *mWeight, string outWeightPath);
    void outputWeight(vector<double> *vWeight, string outputDir);
    void outputDij(vector<vector<double> > *dij, string outDijPath);
    void outputDose(vector<double> *dose, string outputDir);
    void outputObjValue(vector<double> *objValue, string outputDir);
    void outputDVH(vector<double> *resultDose, string outputDir, double dvhResolution = 0.01);


private:
    /***************    store data which read from files            ***************/
    //store dose matrix size which read from dosegrid file
    unsigned int m_nSizeX;
    unsigned int m_nSizeY;
    unsigned int m_nSizeZ;

    unsigned int m_nBeamletNumTotal;
    vector<int> m_vFieldBeamletNum;
    //unsigned int m_nWeightNumTotal;

    //store structure data which read from structure files
    vector<CStructure> m_vStructures;

    //store field data which read from SpotField_#.ca files
    vector<int> m_vDijIndex;
    vector<vector<double> > m_vDijTotal; //row * line = point * beamlet(weight number)

    //store field data which read from SpotWeightO_#.txt files   
    vector<double> m_vWeightTotal;

    //store dose 
    vector<double> m_vDose;

    //store EUD
    vector<double> m_vEUD;
};

#endif